 
// A. TOMPSETT 8/2018: Code to estimate panel IV regression adjusted with centred covariates 

/*-----------------------------------------------------------------------------

 [BETA VERSION]

 This may contain errors. Please notify me of any errors you find.
 
 ------------------------------------------------------------------------------

 Syntax:
 
 xtivreg2_centred Yvar X1varlist (X2varlist = Zvarlist), control(control_vars) 

 Function regresses the outcome variable Yvar on the list of treated variables Xvarlist, controlling for the variables listed in control_vars.  Before including the variables in control_vars as controls, the function first centers or demeans the variables with respect to the same sample and weighting function used in the regression.  
 
 The function accepts most options that xtivreg2 accepts.  

 ------------------------------------------------------------------------------
 
 Requred arguments: 
 
 Yvar: dependent variable  
 X1varlist: independent variables 
 X2varlist: endogenous variables
 Zvarlist: instruments
  control: control variables
 ------------------------------------------------------------------------------
 
 Options:
 
 See STATA help file for xtivreg2.  
 
 ------------------------------------------------------------------------------

 References:

Lin, W. (2013). Agnostic notes on regression adjustments to experimental data: Reexamining Freedman’s critique. The Annals of Applied Statistics, 7(1), 295-318.
      
and 

Gibbons, C. E., Serrato, J. C. S., & Urbancic, M. B. (2018). Broken or fixed effects? Journal of Econometric Methods (forthcoming)

and

Imbens, G. W., & Rubin, D. B. (2015). Causal inference in statistics, social, and biomedical sciences. Cambridge University Press.
 
 -----------------------------------------------------------------------------*/

program xtivreg2_centered, eclass byable(recall) sortpreserve

syntax [anything(name=0)] [if] [in] [fweight aweight iweight], control(varlist) [*]

/*--------PARSING COMMANDS AND SETUP-------*/

//establish sample

capture drop touse
marksample touse				
gen touse = `touse'

//Extract outcome variables and treatment variables

//parsing variables
loc Y = word("`anything'",1)		

local n 0

gettoken lhs 0 : 0, parse(" ,[") match(paren)
IsStop `lhs'
if `s(stop)' {
	error 198
}
while `s(stop)'==0 {
	if "`paren'"=="(" {
		local n = `n' + 1
		if `n'>1 { 
capture noi error 198 
di in red `"syntax is "(all instrumented variables = instrument variables)""'
exit 198
		}
		gettoken p lhs : lhs, parse(" =")
		while "`p'"!="=" {
			if "`p'"=="" {
capture noi error 198 
di in red `"syntax is "(all instrumented variables = instrument variables)""'
di in red `"the equal sign "=" is required"'
exit 198 
			}
			local endo `endo' `p'
			gettoken p lhs : lhs, parse(" =")
		}
* To enable Cragg HOLS estimator, allow for empty endo list
		if "`endo'" != "" {
			tsunab endo : `endo'
		}
* To enable OLS estimator with (=) syntax, allow for empty exexog list
		if "`lhs'" != "" {
			tsunab exexog : `lhs'
		}
	}
	else {
		local inexog `inexog' `lhs'
	}
	gettoken lhs 0 : 0, parse(" ,[") match(paren)
	IsStop `lhs'
}
local 0 `"`lhs' `0'"'

tsunab inexog : `inexog'
tokenize `inexog'
local lhs "`1'"
local 1 " " 
local inexog `*'
		
		
//center variables and create interaction terms

capture drop *czz

disp "Here are the mean values of the control variable(s) used in the centering process."

foreach controlvar in `control' {
	quietly: summarize `controlvar' if `touse' & `lhs' != . [`weight'`exp'], meanonly
	quietly: gen double czz_`controlvar'_czz = `controlvar' - r(mean)
	disp r(mean)
	
	local inexog_empty = 1
	local exexog_empty = 1

	
	foreach treatvar in `inexog' {
		quiet gen double tzz_`treatvar'_`controlvar'_czz = `treatvar' * czz_`controlvar'_czz
		local inexog_empty = 0
	}
	
	foreach treatvar in `endo' {
		quiet gen double enzz_`treatvar'_`controlvar'_czz = `treatvar' * czz_`controlvar'_czz
	}
	
	foreach treatvar in `exexog' {
		quiet gen double exzz_`treatvar'_`controlvar'_czz = `treatvar' * czz_`controlvar'_czz
		local exexog_empty = 0
	}	
}

//run regression

disp "endo = " "`endo'"
disp "inexog = " "`inexog'"
disp "exexog = " "`exexog'"
disp "inexog_empty ="  "`inexog_empty'"
disp "exexog_empty ="  "`exexog_empty'"

local controls =  ""

if `inexog_empty' == 0 {
	local controls = "`controls' tzz*czz" 
}

local ivspec = "(`endo' = `exexog')"

if `exexog_empty' == 1 {
	local ivspec = "" 
}

if `exexog_empty' == 0 {
	local controls = "`controls' exzz*czz" 
}

xtivreg2 `lhs' `inexog'  `controls' `ivspec' [`weight'`exp'] if `touse', `options' 

capture drop *czz

end

program define IsStop, sclass
				/* sic, must do tests one-at-a-time, 
				 * 0, may be very large */
	if `"`0'"' == "[" {		
		sret local stop 1
		exit
	}
	if `"`0'"' == "," {
		sret local stop 1
		exit
	}
	if `"`0'"' == "if" {
		sret local stop 1
		exit
	}
* per official ivreg 5.1.3
	if substr(`"`0'"',1,3) == "if(" {
		sret local stop 1
		exit
	}
	if `"`0'"' == "in" {
		sret local stop 1
		exit
	}
	if `"`0'"' == "" {
		sret local stop 1
		exit
	}
	else	sret local stop 0
end

exit


